added some development tools
[windows-sources.git] / developer / Samples / NET Standard / ParallelExtensionsExtras / CoordinationDataStructures / SerialTaskQueue.cs
blob27eea0f1d4b5f65d75ab728309f11111c5b29610
1 //--------------------------------------------------------------------------
2 //
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 //
5 // File: SerialTaskQueue.cs
6 //
7 //--------------------------------------------------------------------------
9 using System.Collections.Generic;
10 using System.Diagnostics;
12 namespace System.Threading.Tasks
14 /// <summary>Represents a queue of tasks to be started and executed serially.</summary>
15 public class SerialTaskQueue
17 /// <summary>The ordered queue of tasks to be executed. Also serves as a lock protecting all shared state.</summary>
18 private Queue<object> _tasks = new Queue<object>();
19 /// <summary>The task currently executing, or null if there is none.</summary>
20 private Task _taskInFlight;
22 /// <summary>Enqueues the task to be processed serially and in order.</summary>
23 /// <param name="taskGenerator">The function that generates a non-started task.</param>
24 public void Enqueue(Func<Task> taskGenerator) { EnqueueInternal(taskGenerator); }
26 /// <summary>Enqueues the non-started task to be processed serially and in order.</summary>
27 /// <param name="task">The task.</param>
28 public Task Enqueue(Task task) { EnqueueInternal(task); return task; }
30 /// <summary>Gets a Task that represents the completion of all previously queued tasks.</summary>
31 public Task Completed() { return Enqueue(new Task(() => { })); }
33 /// <summary>Enqueues the task to be processed serially and in order.</summary>
34 /// <param name="taskOrFunction">The task or functino that generates a task.</param>
35 /// <remarks>The task must not be started and must only be started by this instance.</remarks>
36 private void EnqueueInternal(object taskOrFunction)
38 // Validate the task
39 if (taskOrFunction == null) throw new ArgumentNullException("task");
40 lock(_tasks)
42 // If there is currently no task in flight, we'll start this one
43 if (_taskInFlight == null) StartTask_CallUnderLock(taskOrFunction);
44 // Otherwise, just queue the task to be started later
45 else _tasks.Enqueue(taskOrFunction);
49 /// <summary>Called when a Task completes to potentially start the next in the queue.</summary>
50 /// <param name="ignored">The task that completed.</param>
51 private void OnTaskCompletion(Task ignored)
53 lock (_tasks)
55 // The task completed, so nothing is currently in flight.
56 // If there are any tasks in the queue, start the next one.
57 _taskInFlight = null;
58 if (_tasks.Count > 0) StartTask_CallUnderLock(_tasks.Dequeue());
62 /// <summary>Starts the provided task (or function that returns a task).</summary>
63 /// <param name="nextItem">The next task or function that returns a task.</param>
64 private void StartTask_CallUnderLock(object nextItem)
66 Task next = nextItem as Task;
67 if (next == null) next = ((Func<Task>)nextItem)();
69 if (next.Status == TaskStatus.Created) next.Start();
70 _taskInFlight = next;
71 next.ContinueWith(OnTaskCompletion);